(function (){
	/*
		TODO -jsdoc-toolkit / JsDoc -tests unitaires
                date:20110115
	*/

    /*mummy*/

    var mum = {
        name_space:null,
        
        NameSpace:function(name_of_namespace){
            mum.name_space = name_of_namespace;
            window[name_of_namespace]={};
        },
        
        EndNameSpace:function(){
            mum.name_space = null;
        },
        
        
        Interface:function(interface_def){
            var interface_i = new interface_def();
            var interface_name = (interface_i).constructor.name;
            //record new interface
            
            ////window[interface_name]= interface_i;
            
            
            if(mum.name_space===null){
                window[interface_name]= new interface_def();
            }else{
                window[mum.name_space][interface_name]= new interface_def();
            }
            return interface_i;
            
        },

        /*class def*/		
        Class:function(){
            //console.log(mum.name_space);
            var 
                p_class,
                construct,
                constructor_name;
            
            if(arguments[1]!==undefined){/*abstract class*/
                p_class=arguments[1];
                //if(arguments[0]===$abstract){console.log("abstract");}
            }else{
                p_class=arguments[0];
            }

            construct = (new p_class.$define());
            constructor_name = construct.constructor.name;

            /*static members*/
            if(p_class.$static!==undefined){
                var stMember;
                for(stMember in p_class.$static){
                    p_class.$define[stMember]=p_class.$static[stMember];
                }
            }
            
            /*inheritance*/
            if(p_class.$extends!==undefined){
                    p_class.$define.prototype = new p_class.$extends();
                    /*TODO: vérifier les 2 lignes ci-dessous*/
                    p_class.$define.prototype.parent = new p_class.$extends(); /*? j'ai un trou de mémoire*/
                    p_class.$define.parent = new p_class.$extends(); /*? j'ai un trou de mémoire*/
            }

            /*save constructor name for get instance of*/
            p_class.$define.prototype.getTypeName = function(){return constructor_name;};
            p_class.$define.getTypeName = function(){return constructor_name;};

            p_class.$define.prototype.getType = function(){return construct;};
            p_class.$define.getType = function(){return construct;};

            /*abstract Class*/
            if(arguments[0]===$abstract){
                p_class.$define.isAbstract = true;
            }else{
                p_class.$define.isAbstract = false;
            }

            /*interface*/
            if(p_class.$implements!==undefined){
                var 
                    inst = new p_class.$define(), 
                    member;

                p_class.$define.prototype.interfaces = p_class.$implements;
                p_class.$define.interfaces = p_class.$implements;

                //plutôt while loop
                var i;
                for(i=0; i < p_class.$implements.length; i++){

                    for(member in p_class.$implements[i]){

                        if(inst[member]!==undefined){

                            if(inst[member]["getType"]==undefined && p_class.$implements[i][member]["getType"]==undefined ){

                                if(typeof(inst[member]) !== typeof(p_class.$implements[i][member]) ){
                                    /*implemented but bad type*/
                                    throw   'Class '+constructor_name+', Interface '+p_class.$implements[i].constructor.name+
                                            ' : bad type : '+member+
                                            ' implemented, but '+
                                            typeof(inst[member])+' instead of '+
                                            typeof(p_class.$implements[i][member]);
                                }

                            }

                            if(inst[member]["getType"]!==undefined && p_class.$implements[i][member]["getType"]!==undefined ){
                                if(inst[member].getType() !== p_class.$implements[i][member].getType() ){
                                    /*implemented but bad type*/
                                    throw 	'Class '+constructor_name+', Interface '+p_class.$implements[i].constructor.name+
                                            ' : bad type : '+member+
                                            ' implemented, but '+
                                            inst[member].getTypeName()+' instead of '+
                                            p_class.$implements[i][member].getTypeName();
                                }
                            }

                            if(inst[member]["getType"]==undefined && p_class.$implements[i][member]["getType"]!==undefined ){
                                throw 	'Class '+constructor_name+', Interface '+p_class.$implements[i].constructor.name+
                                        ' : bad type : '+member+
                                        ' implemented, but '+
                                        typeof(inst[member])+' instead of '+
                                        p_class.$implements[i][member].getTypeName();
                            }

                            if(inst[member]["getType"]!==undefined && p_class.$implements[i][member]["getType"]==undefined ){
                                throw 	'Class '+constructor_name+', Interface '+p_class.$implements[i].constructor.name+
                                        ' : bad type : '+member+
                                        ' implemented, but '+
                                        inst[member].getTypeName()+' instead of '+
                                        typeof(p_class.$implements[i][member]);
                            }

                        }else{
                            /*not implemented*/
                            throw   member+' not implemented in Class '+constructor_name+
                                    ', Interface '+p_class.$implements[i].constructor.name;
                        }

                    }/*end for*/
                }/*end for*/
            }/*end interface*/


            /*properties*/
            /*attention 2 fois new p_class.$define()*/
            
            if((new p_class.$define()).$properties!==undefined){
                var 
                    properties = (new p_class.$define()).$properties, 
                    getSetMember;
                    
                for(getSetMember in properties){
                    if(properties[getSetMember].get!==undefined){
                        p_class.$define.prototype.__defineGetter__(getSetMember, properties[getSetMember].get);
                    }
                    if(properties[getSetMember].set!==undefined){
                        p_class.$define.prototype.__defineSetter__(getSetMember, properties[getSetMember].set);
                    }	
                }
            }
            
            /*record new type*/
            ////window[constructor_name]= p_class.$define;
            
            //console.log(name_space);
            
            if(mum.name_space===null){
                window[constructor_name]= p_class.$define;
            }else{
                window[mum.name_space][constructor_name]= p_class.$define;
            }
            
            return p_class.$define;/*utile ?*/

        },/*End Class*/

        Get:function(class_def_or_instance){

            return new function(){
                /*get instance of class with params*/
                this.getNew=function(){/*class_def*/
                    var instance = new class_def_or_instance();

                    if(!class_def_or_instance.isAbstract){

                        if(instance[instance.getTypeName()]!==undefined){
                            instance[instance.getTypeName()].apply(instance,arguments);
                            //instance['getTypeName'] = function(){return this.className;}
                        }/*else{/no constructor}*/

                    }else{
                        throw instance.getTypeName()+' is an abstract class';
                    }
                    
                    return instance;
                };

                this.New = this.getNew;
                this.getInstance = this.getNew;

                /*--- TOOLS ---*/
                /*implements interface ?*/
                this.Implements=function(interf){/*instance*/
                    var 
                        ret = false,
                        i;
                    if(class_def_or_instance.interfaces!==undefined){
                        /*TODO: plutôt while loop : array*/
                        for(i=0; i < class_def_or_instance.interfaces.length; i++){
                            if(class_def_or_instance.interfaces[i]==interf){ret=true;break;}
                            /*sortir de boucle next quand interface triuvée*/
                        }
                    }
                    return ret;
                };

                /*if is a "type" then true*/
                this.Is = function(class_def){/*instance*/
                    /*var ret = false;
                    if(class_def_or_instance.getType().constructor == class_def){ret=true;};
                    return ret;*/
                    return class_def_or_instance instanceof class_def;
                };

                this.CopyTo = function(o_target){
                    var m;
                    for(m in class_def_or_instance){
                        if(typeof(class_def_or_instance[m])!=="function"){
                            o_target[m] = class_def_or_instance[m];
                        }
                    }
                    return o_target;
                };

                this.MergeWith = function(o_target){
                    var m;
                    for(m in class_def_or_instance){
                        o_target[m] = class_def_or_instance[m];
                    }					
                    return o_target;
                };

                /*functionnal inheritance*/
                this.Extends = function(Parent){
                    var 
                        m,
                        fparent=new Parent();
                    for(m in fparent){
                        if((m!="getType")||(m!="getTypeName")){
                            class_def_or_instance[m] = fparent[m];
                        }
                    }				
                };
            };/*End return new function*/
        }/*End Get*/



    };/*END var mum*/

    /*
    if(!window.NameSpace){window.NameSpace=mum.NameSpace;}
    if(!window.EndNameSpace){window.EndNameSpace=mum.EndNameSpace;}
    */

    if(!window.Class){window.Class=mum.Class;}
    if(!window.$abstract){window.$abstract="abstract";}

    if(!window.Interface){window.Interface=mum.Interface;}
    if(!window.NameSpace){window.NameSpace=mum.NameSpace;}
    if(!window.EndNameSpace){window.EndNameSpace=mum.EndNameSpace;}
    
    if(!window.$){window.$=mum.Get;}
    if(!window.Get){window.Get=mum.Get;}

	
})();


